home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Experimental BBS Explossion 3
/
Experimental BBS Explossion III.iso
/
gus
/
mikmod2.zip
/
MIKMOD.C
next >
Wrap
C/C++ Source or Header
|
1993-12-03
|
7KB
|
358 lines
/*
MIKMOD.C Programmed by MikMak of Unicorn Design
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
#include <dos.h>
#include <string.h>
#include <alloc.h>
#include <conio.h>
#include "forte.h"
#include "gf1proto.h"
#include "extern.h"
#include "ultraerr.h"
#include "modload.h"
#include "modplay.h"
#include "mytypes.h"
ULTRA_CFG config;
ULONG Ultra[31];
/* Ultra[] holds the sample dram adresses
of the 31 samples of a module */
void SetBPM(int bpm)
{
/* The player routine has to be called (bpm*50)/125 times a second,
so the interval between calls takes 125/(bpm*50) seconds (amazing!).
The Timer1 handler has a resolution of 160 microseconds.
So the timer value to program:
(125/(bpm*50)) / 1.6e-4 = 15625/bpm
*/
UltraStartTimer(1,15625/bpm);
}
void HandleTimer1()
{
int t;
SAMPLEINFO *d;
UWORD period,vol;
ULONG base;
static int odd=0;
/* Do not service the odd calls to this handler .. This
effectively makes this a 2*80=160 microsecond handler */
if(odd^=1) return;
MP_HandleTick(); // Call the player routine
for(t=0;t<ml_numchn;t++){ // for each channel
/* get sample period and volume */
period=mp_audio[t].period;
if(period<100) period=100; // limit the period value
if(period>8000) period=8000;
vol=((UWORD)511*mp_audio[t].volume)/64;
UltraSetFrequency(t,(ULONG)3579546/period);
UltraVectorLinearVolume(t,vol,60,0);
// Check if the sample has to be restarted
if(mp_audio[t].kick){
// Get sample dram address
base=Ultra[mp_audio[t].sample];
UltraVoiceOff(t,0); // <- This seems to be neccecary
if(mp_audio[t].loop<mp_audio[t].size){
// Start a looping sample, start at volume 0
UltraSetLinearVolume(t,0);
// Then, a fast ramp to current volume
UltraVectorLinearVolume(t,vol,60,0);
UltraStartVoice(t,
base+mp_audio[t].start,
base+mp_audio[t].loop,
base+mp_audio[t].size,0x8);
}
else{
// Start a one-shot sample
UltraSetLinearVolume(t,0);
UltraVectorLinearVolume(t,vol,60,0);
UltraStartVoice(t,
base+mp_audio[t].start,
base+mp_audio[t].start,
base+mp_audio[t].size,0);
}
mp_audio[t].kick=0;
}
}
SetBPM(mp_bpm); // Update beats-per-minute
}
int UltraGetCfg(ULTRA_CFG *config)
{
char *ptr;
config->base_port = 0x220;
config->dram_dma_chan = 1;
config->adc_dma_chan = 1;
config->gf1_irq_num = 11;
config->midi_irq_num = 5;
if((ptr=getenv("ULTRASND"))==NULL) return FALSE;
if(sscanf(ptr,"%x,%d,%d,%d,%d"
,&config->base_port,
&config->dram_dma_chan,
&config->adc_dma_chan,
&config->gf1_irq_num,
&config->midi_irq_num)!=5) return FALSE;
return(TRUE);
}
void UltraDownloadX(UBYTE *data_ptr,UBYTE control,ULONG dram_loc,UWORD len,int wait)
/*
Identical to UltraDownLoad() except this one handles
dram_loc's that aren't on a 32-byte boundary.
*/
{
/* Dram location not on a 32 byte boundary ? */
while(len>0 && (dram_loc&31)){
/* Slowly 'poke' the odd
samples into gus dram */
UltraPokeData(config.base_port,dram_loc,*data_ptr);
data_ptr++;
dram_loc++;
len--;
}
// The rest goes fast...
if(len>0) UltraDownload(data_ptr,control,dram_loc,len,wait);
}
ULONG UltraFileload(FILE *fp,UBYTE control,ULONG dram_loc,ULONG size)
/*
This function directly loads data from a file into gus dram.
returns the number of bytes actually loaded.
*/
{
ULONG todo,total=0,done;
char *buffer;
if((buffer=malloc(8000))==NULL) return 0;
do{
todo=(size>8000)?8000:size;
done=fread(buffer,1,todo,fp);
UltraDownloadX(buffer,control,dram_loc,done,TRUE);
total+=done;
dram_loc+=done;
size-=done;
} while( size>0 && (done==todo) );
free(buffer);
return total;
}
UBYTE UltraPeek(ULONG address)
{
return(UltraPeekData(config.base_port,address));
}
void UltraPoke(ULONG address,UBYTE val)
{
UltraPokeData(config.base_port,address,val);
}
int MyLoader(int samplenr,FILE *fp,ULONG ssize)
/*
callback routine for the MODLOAD module.
samplenr :Number of the sample that is being loaded
fp :file ptr to that sample
size :Size of the sample that is being loaded (in bytes)
*/
{
// Allocate GUS dram and store the address in Ultra[samplenr]
// Alloc 1 byte more for anticlick measures. see below.
if(UltraMemAlloc(ssize+1,&Ultra[samplenr])!=ULTRA_OK)
return 0;
// Load the sample
if(UltraFileload(fp,DMA_8|DMA_NO_CVT,Ultra[samplenr],ssize)!=ssize)
return 0;
if(ml_samples[samplenr].replen>2){ // looping sample ?
/* Anticlick for looping samples:
Copy the first byte in the loop
one place beyond the end of the loop */
UltraPoke(Ultra[samplenr]+ml_samples[samplenr].reppos+ml_samples[samplenr].replen,
UltraPeek(Ultra[samplenr]+ml_samples[samplenr].reppos));
}
else{
/* Anticlick for one-shot samples:
Zero the byte beyond the end of the sample.
*/
UltraPoke(Ultra[samplenr]+ssize,0);
}
return 1;
}
void PlayMod(char *file)
{
int t;
/* Tell MODLOAD to use 'MyLoader'
as the sample loader */
ML_RegisterSampleLoader(MyLoader);
// Load the module and convert the patterninfo
if(!ML_LoadModule(file,NULL)){
printf("Error loading module %s: %s.\n",file,ml_errlist[ml_errno]);
return;
}
printf("Title : %s\n"
"ModType : %s %d channels\n"
"Patterns : %d\n"
"Songlength: %d\n",ml_songname,ml_modtype,ml_numchn,ml_numpat,ml_songlength);
/* Uncomment this if you want to see the samplenames.
for(t=0;t<31;t++){
printf("Sample %d:%s\n",t,ml_samples[t].samplename);
}
*/
for(t=0;t<ml_numchn;t++) UltraSetBalance(t,7+t-(ml_numchn>>1));
// Let's make some noise !
UltraEnableOutput();
SetBPM(125); // Kickstart the timer
printf("Press any key to stop playing...");
// You might want to do something more useful here
getch();
UltraStopTimer(1);
}
int main(int argc,char *argv[])
{
printf("MIKMOD v0.2 or how to make a modplayer using the GUS SDK Toolkit v2.01\n"
"Programmed by MikMak of Unicorn Design. This is SOURCEWARE/PUBLIC DOMAIN\n"
"So you may use my routines as long as you mention my name :)\n"
"E-Mail: mikmak@stack.urc.tue.nl\n\n");
if(argc!=2){
puts("Usage: MIKMOD <modname.mod>");
return -1;
}
/* Get the ULTRASND environment string parameters */
if(!UltraGetCfg(&config)){
puts("Ultrasound env. string not found..");
return -1;
}
/* Set up max. 14 channels */
if(UltraOpen(&config,14)==NO_ULTRA){
printf("No ultrasound card found\n");
return -1;
}
/* Report size of GUS DRAM */
printf("This GUS has %dK of Dram\n",UltraSizeDram());
/* Grab the 80 microsecond timer handler */
UltraTimer1Handler(HandleTimer1);
/* Then try to play the module yeah */
PlayMod(argv[1]);
/* Shut sound down & re-init hardware ... */
UltraClose();
return 0;
}